#include<iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include<stdio.h>

//本次代码属于第一版，没有加内接指令的shell，下一个版本会继续完善

//打印前面的内容
#define FORMAT "[%s@%s %s]# "
#define COMMAND_SIZE 1024

//环境变量表
#define MAXARGC 128
char *g_argv[MAXARGC];
int g_argc = 0; 


//此时我们需要先把我们在日常使用Linux的[内容]打印出来，此时我们需要借助环境变量来完成


const char* GetUSRNAME()
{
  const char* name = getenv("USER");
  return name == nullptr ? "None" : name;
}

const char* GETHOMENAME()
{
  const char* homename = getenv("HOSTNAME");
  return homename == nullptr ? "None" : homename;
}


const char* GETCWD()
{
  const char* cwd = getenv("PWD");
  return cwd == nullptr ? "None" : cwd;
}


//下面这个函数可以提取出pwd当前路径的最后一个名字

std::string DirName(const char *pwd)
{
#define SLASH "/"
    std::string dir = pwd;
    if(dir == SLASH) return SLASH;
    auto pos = dir.rfind(SLASH);
    if(pos == std::string::npos) return "BUG?";
    return dir.substr(pos+1);
}


void MakeCommandLine(char cmd_prompt[],int size)
{
  snprintf(cmd_prompt,size,FORMAT,GetUSRNAME(),GETHOMENAME(),GETCWD());
}


void PrintCommandPrompt()
{
  char prompt[COMMAND_SIZE];
  MakeCommandLine(prompt,sizeof(prompt));
  printf("%s",prompt);
  fflush(stdout);
}


bool GetCommandline(char* out,int size)
{
  //输入字符串。下面这个函数会自动在结尾放个\n，为了美观，所以最好自己手动把它清掉
  char* c = fgets(out,size,stdin);
  if(c == nullptr) return false;
  out[strlen(out) - 1] = 0;  //把\n给清楚了
  if(strlen(out) == 0)  return false;
  return true;
}




bool CommandParse(char* commandline)
{
#define SEP " "
  //因为每次输入的指令都不一样，所以在每次进行命令行分析的时候我们都需要进行清零操作，方便后续的使用
  g_argc = 0;
  g_argv[g_argc++] = strtok(commandline,SEP);  //这个函数的作用是来进行切割的，把第一个参数的字符串给切割，直到遇到第二个字符才停止切割
  while((bool)(g_argv[g_argc++] = strtok(nullptr,SEP))); //strtok 的第一个参数为 nullptr，表示继续分割上一次传入的字符串。SEP 是分隔符集合（例如空格、制表符等）。
  g_argc--;
  return true;

}


void PrintARGV()
{
  for(int i = 0 ; i < g_argc ;i++)
  {
    printf("g_argv[%d]->%s",i,g_argv[i]);
  }
  printf("argc:%d\n",g_argc);
}



void Execute()
{
  pid_t a = fork();
  if(a == 0)  //让子进程执行进程替换
  {
    execvp(g_argv[0],g_argv);
    exit(1);
  }
  waitpid(-1,NULL,0);
  return;
}





int main()
{
  while(true){
   //1.输出命令行提示符，也就是日常我们使用指令时[]的部分i
   PrintCommandPrompt();
   //2.获取用户输入的命令
   char commandline[COMMAND_SIZE];
   if(!GetCommandline(commandline,sizeof(commandline)))
   continue;
   //3.命令行分析（其实是把类似"ls -a -l"，把它切割成"ls"。"-a"，"-l"）   所以我认为这个也可以被称之为命令行切割操作
   CommandParse(commandline);
  // PrintARGV();
   //4.执行命令（进程替换）
    Execute();
  }
   return 0;
}
